package cn.iocoder.yudao.framework.util;

import cn.iocoder.yudao.framework.common.exception.Assertions;
import jakarta.annotation.Nonnull;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * <pre>
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 *  树形列表工具类
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * </pre>
 *
 * @author 山野羡民（1032694760@qq.com）
 * @see cn.hutool.core.lang.tree.TreeUtil
 * @since 2024/05/17
 */
public class TreeUtils {

    /**
     * 构建树节点列表
     */
    public static <ID, NODE extends TreeNode<ID, NODE>> List<NODE> buildTreeList(List<NODE> nodes) {
        if (nodes == null || nodes.isEmpty()) {
            return new ArrayList<>(0);
        }
        List<NODE> treeList = new ArrayList<>();
        Map<ID, NODE> nodeMap = new LinkedHashMap<>(nodes.size());
        for (NODE node : nodes) {
            if (node == null) {
                continue;
            }
            nodeMap.put(node.getId(), node);
        }
        for (NODE node : nodeMap.values()) {
            NODE parent = nodeMap.get(node.getParentId());
            if (node.getParentId().toString().equals("0")) {
                node.setParentName("顶级");
            }
            if (parent != null && !(node.getId().equals(parent.getId()))) {
                node.setParentName(parent.getName());
                List<NODE> children = parent.getChildren();
                Assertions.notNull(children, "节点[%s]的父级节点[%s]没有对应的子节点列表".formatted(node.getName(), parent.getName()));
                children.add(node);
                continue;
            }
            treeList.add(node);
        }
        return treeList.stream().sorted().toList();
    }

    /**
     * 根据父级ID构建树节点列表
     */
    public static <ID, NODE extends TreeNode<ID, NODE>> List<NODE> buildTreeList(List<NODE> nodes, ID parentId) {
        if (nodes == null || nodes.isEmpty()) {
            return new ArrayList<>(0);
        }
        List<NODE> treeList = new ArrayList<>();
        for (NODE node : nodes) {
            if (node == null) {
                continue;
            }
            if (node.getParentId().toString().equals("0")) {
                node.setParentName("顶级");
            }
            if (node.getParentId().equals(parentId)) {
                treeList.add(findChildren(nodes, node));
            }
        }
        return treeList.stream().sorted().toList();
    }

    /**
     * 递归查找子节点
     */
    private static <ID, NODE extends TreeNode<ID, NODE>> NODE findChildren(List<NODE> nodes, NODE parentNode) {
        for (NODE node : nodes) {
            if (node == null) {
                continue;
            }
            if (node.getParentId().equals(parentNode.getId())) {
                node.setParentName(parentNode.getName());
                List<NODE> children = parentNode.getChildren();
                Assertions.notNull(children, "节点[%s]的父级节点[%s]没有对应的子节点列表".formatted(node.getName(), parentNode.getName()));
                children.add(findChildren(nodes, node));
            }
        }
        return parentNode;
    }

    public interface TreeNode<ID, NODE extends TreeNode<ID, NODE>> extends Comparable<NODE> {

        ID getId();

        String getName();

        ID getParentId();

        String getParentName();

        void setParentName(String parentName);

        @Nonnull
        List<NODE> getChildren();

    }

}
